/*
 *   mapDNS.c
 *       
 *   Copyright 2010 yorks <stuyorks@gmail.com>
 *        
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *         
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *        
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *   MA 02110-1301, USA.
 *   
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <glib.h> //read the ini config file
#include <getopt.h> //parse the argv
#include <sys/stat.h> //stat, check file exist.
#include <dirent.h> //read all the domain config files
#include <pthread.h> //update config file thread

#include "exDNS.h" //local header file
#include "ping.h"
#include "log.h"
 
#define SERV_PORT 53
#define DNSLISTFILENAME "dnsList.db"
#define DISTANCEFILESUFFIX "distance.db"

const char* program_name; //this program name
static char data_dir[1024]; //database(domain,dnsIPlist...) directory
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
char log_content[2048]; /* content write to log file */


int
main(int argc,char **argv) {

    program_name = argv[0]; //name of this program
    parse_opt (argc, argv); //set file database directory by -d option
    check_file_exit(); //check the directory and config file exist.
    //update_config_files();
    pthread_t thread_id;
    /*pthread_attr_t p_attr;
    pthread_attr_init(&p_attr);
    pthread_attr_setdetachstate(&p_attr, PTHREAD_CREATE_DETACHED);*/
    int ret;
    //ret=pthread_create(&thread_id, &p_attr, (void *)update_config_files, NULL);
    ret=pthread_create(&thread_id, NULL, (void *)update_config_files, NULL);
    if(ret!=0){
	    printf ("Create pthread error!\n");
	    exit (1);
    }
    //pthread_attr_destroy(&p_attr);
    //pthread_detach(thread_id);
    int z;  /*result of bind, recvfrom, sendto*/
    struct sockaddr_in adr_serv;/* AF_INET server */
    struct sockaddr_in adr_clnt;/* AF_INET client */
    int len_inet;               /* length  */
    int s;                      /* Socket */
    unsigned char dgram[65535];        /* Recv buffer */
    struct DNS_HEADER *dns = NULL;
    struct QUESTION *question = NULL;

    /*
     *  Create a UDP socket to use :
     */
    s = socket(AF_INET,SOCK_DGRAM,0);
	if(s==-1){
        perror ("socket");
        exit(1);
	}
 
    /*
     * Create a socket address, for use
     * with bind(2) :
     */
    memset(&adr_serv,0,sizeof(adr_serv));
    adr_serv.sin_family = AF_INET;
    adr_serv.sin_port = htons(SERV_PORT);
    adr_serv.sin_addr.s_addr = htonl(INADDR_ANY);

    len_inet = sizeof(adr_serv);
 
    /*
     * Bind a address to our socket, so that
     * client programs can contact this
     * server:
     */
    z = bind(s,
        (struct sockaddr *)&adr_serv,
        len_inet);
	
    if(z==-1){
        perror ("bind");
        exit(1);
	 }
 
    /*
     * Now wait for requests:
     */
    for (;;) {
       /*
        * Block until the program receives a
        * datagram at our address and port:
        */
        socklen_t len_clnt = sizeof(adr_clnt);
        z = recvfrom(s,                /* Socket */
            dgram,           /* Receiving buffer */
            65535,   		/* Max recv buf size */
            0,              /* Flags: no options */
            (struct sockaddr *)&adr_clnt,/* Addr */
            &len_clnt);    /* Addr len, in & out */
	if(z==-1){
            perror ("recv");
           // exit(1);
	}
    /* According  to the client ip address to.
     * get its location, if the location
     * unknown(not in the dnsList.db), 
     * continue to recvfrom.
     * */
    char *ipaddr=inet_ntoa(adr_clnt.sin_addr);
    char localtion[10];
    int hasDNS = getLocation(ipaddr, localtion);
    if(hasDNS==0){
          sprintf(log_content, "客户的本地DNS的IP为:%s 对应的城市为:%s", ipaddr, localtion);
          log_2_file(log_content);

    }
    else{
          sprintf(log_content, "客户的本地DNS的IP为:%s 找不到对应的城市!请将手动加入数据库dnsList.db !", ipaddr);
          log_2_file(log_content);
          continue;
    }


    /*
     * We format all the recv data to DNS format.
     * To fetch the things what we need easily.
     * */
    dns = (struct DNS_HEADER*) dgram;

    /* 
     *  id:
     *    generates any kind of query.  copied the 
     *    corresponding reply and can be used by the 
     *    requester to match up replies to outstanding 
     *    queries.
     **/
    //printf("id: %d\n",ntohs(dns->id));

    /*
     * This program only can do for one question for one 
     * time. So It don'nt need to know q_count.
     * */
    //printf("Questions: %d",ntohs(dns->q_count));

    
    /*QNAME :a domain name represented as a sequence of labels, where
     *       each label consists of a length octet followed by that
     *       number of octets.  The domain name terminates with the
     *       zero length octet for the null label of the root.  Note
     *       that this field may be an odd number of octets; no
     *       padding is used.
     *       e.g.:www.stu.edu.cn --> 3www3stu3edu2cn0
     **/
    unsigned char qname[256]; /*restricted to 255 octets  RFC 1035 */
    int next=0;
    while(0 != (int)dgram[sizeof(struct DNS_HEADER)+next]){
        //qname[next]=dgram[sizeof(struct DNS_HEADER)+next];
        //printf("%d\n",qname[next]);
        next++;
    }
    //qname[next]=dgram[sizeof(struct DNS_HEADER)+next];
    int len_qname;
    len_qname = next+1;
    /*Attention:
     *       Now NEXT is how many bytes the Qname have. 
     *       qname[LAST]=0; That is: LAST=NEXT.
     *       So, copy NEXT+1(len_qname) bytes to qname.
     * */
	memcpy(qname, dgram+sizeof(struct DNS_HEADER), len_qname);

    /*dnsName use to conver to urlname--Domain_file need.*/
    unsigned char dnsName[256];
	memcpy(dnsName, dgram+sizeof(struct DNS_HEADER), len_qname);

    unsigned char *urlName=NULL;
    urlName = readName(dnsName);
    char domainDIR[2048];
    sprintf(domainDIR, "%s%s", data_dir, urlName);
    //strcat(domainDIR, (char*)urlName);//the DomainFile path.
    //puts(domainDIR);
    char record[255];// A record.--ip address.
    if(getArecord2((unsigned char*)domainDIR, localtion, record)!=0){
        //do not have this zone file. So, continue to recvfrom...
	    //printf("Skip: do not have this domain in data dir.\n");
        sprintf(log_content, "没有该域名:%s的信息，请添加该域名信息!", urlName);
        log_2_file(log_content);
	    continue;
    }
    
    /*Format the The remaining dgram(except DNS_HEADER and QNAME,
     * DNS_HEADER+len_qname) to QUESTION.
     * 
     * */
    question = (struct QUESTION *)&dgram[sizeof(struct DNS_HEADER)+len_qname];
    //printf("qtype:%d\n", ntohs(question->qtype));
    //printf("qclass:%d\n", ntohs(question->qclass));
    int isIPv6 = 0;
    if(1 != ntohs(question->qtype)){
        //qtype(1: search A record. 28: AAA)
        //qclass(1: internet class)
        //this program only to response the A record.
        //So, skip it. continue to recv...
        if(28==ntohs(question->qtype)){
            isIPv6 = 1;
        }
        else{
            //printf("Skip: Request is not a internet A record.\n");
            sprintf(log_content, "查询的不是A记录!");
            log_2_file(log_content);
            continue;
        }
    }


    /*Generate response Package*/
    struct DNS_HEADER *responHeader = NULL;
    unsigned char buf[65536]; /*buf want to response to client*/

    responHeader = (struct DNS_HEADER *)buf;

    responHeader->id = dns->id;
//    responHeader->qr = 1; /*This is a response(0: querty)*/
//    responHeader->opcode = 0; /*This is a standard query*/
//    responHeader->aa = 0; /*Server is an authority(0: is not authority)*/
//    responHeader->tc = 0; /*This message is not truncated do not Recursion Desired*/
//    responHeader->rd = 0; /*Recursion Desired: Don't do query recursively*/
//    responHeader->ra = 0; /*Recursion available: Server can do recursive queries*/
//    responHeader->z = 0;
//    responHeader->ad = 0;
//    responHeader->cd = 0;
//    responHeader->rcode = 0;
    responHeader->flag = htons(0x8480);
    responHeader->q_count = htons(1); //1 question
    if(!isIPv6){
        responHeader->ans_count = htons(1);
    }
    else{
        responHeader->ans_count = htons(0);
    }
    responHeader->auth_count = htons(0);
    responHeader->add_count = htons(0);
    /*end header*/

     int len_Header;
     len_Header  = sizeof(struct DNS_HEADER);

    /*Querty start
     *       +~~~ \------QNAME-----\
     *QUERYT-|    |------QTYPE-----|+~~~~+
     *       +~~~ |------QCLASS----|+~~~~|~~QUESTION
     * */
    next=0;
    while(0!= qname[next]){
       //printf("%d\n",qname[next]);
	   buf[len_Header+next]=qname[next];
       next++;
    }
	buf[len_Header+next]= qname[next]; /*  QNAME  */
    len_qname = next+1;
    //printf("%d, %d\n", buf[len_Header+next], len_qname);

    struct QUESTION *qes = NULL;
    qes = (struct QUESTION*)&buf[len_Header+len_qname];
    qes->qtype = question->qtype;
    qes->qclass = question->qclass;
    /*end Querty*/
    int len_Querty;
    len_Querty  = len_qname+sizeof(struct QUESTION);

    /*Answer start
     * 
     * \-----------QNAME--------\
     * |-----------TYPE---------|~~~~~~+
     * |-----------CLASS--------|      |
     * |------------TTL---------|      |---R_DATA
     * |----------RDLENGTH------|~~~~~~+
     * \-----------RDATA--------\
     *
     * */

      /*name start*/

    next=0;
    while(0!= qname[next]){
       //printf("%d\n",qname[next]);
	   buf[len_Header+len_Querty+next]=qname[next];
       next++;
    }
	buf[len_Header+len_Querty+next]= qname[next]; /*with 0 ends*/
      /*end name*/
    
      /*type, class, ttl, data_len start*/
    struct R_DATA *r_data = NULL;
    r_data = (struct R_DATA*)&buf[len_Header+len_Querty+len_qname];
    r_data->type = htons(1);     /*type: A*/
    r_data->_class = htons(1);   /*IPV4 internet class*/
    r_data->ttl = htonl(86400);  /*1D*/
    r_data->data_len = htons(4); /* an unsigned 16 bit integer that specifies the length in octets of the RDATA field. */
      /*end type, class, ttl, data_len*/

      /*RDATA Start A Record*/
    //char *ip_addr = NULL;
    //ip_addr = "10.14.2.168";
    char ip_addr[255];
    strcpy(ip_addr, record);
    struct in_addr *ip = NULL;
    ip = (struct in_addr*)&buf[len_Header+len_Querty+len_qname+sizeof(struct R_DATA)];
    ip->s_addr = inet_addr(ip_addr);
      /*End RDATA*/
    /* end answer */

    int len_Answer;
    len_Answer = len_qname+sizeof(struct R_DATA)+sizeof(struct in_addr);

    /*Authoritative start*/
    unsigned char zoneName[255]="stu.edu.cn";
    unsigned char zoneDnsName[255];
    change2dnsNameFormat(zoneDnsName,zoneName);
    next = 0;
    while(0!=(int)zoneDnsName[next]){
        buf[len_Header+len_Querty+len_Answer+next] = zoneDnsName[next];
        //printf("%d\n", zoneDnsName[next]);
        next++;
    }
    buf[len_Header+len_Querty+len_Answer+next] = zoneDnsName[next]; 
    int len_zone_name;
    len_zone_name = 0;
    len_zone_name = next+1;//zone name end

      /*type, class, ttl, data_len start*/
    struct R_DATA *r_data_auth = NULL;
    r_data_auth = (struct R_DATA*)&buf[len_Header+len_Querty+len_Answer+len_zone_name];
    r_data_auth->type = htons(2);     /*type: NS*/
    r_data_auth->_class = htons(1);   /*IPV4 internet class*/
    r_data_auth->ttl = htonl(86400);  /*1D*/
    r_data_auth->data_len = htons(5); /* an unsigned 16 bit integer that specifies the length in octets of the RDATA field. */
      /*end type, class, ttl, data_len*/    
   unsigned char nsName[255]= "ns.stu.edu.cn";
   unsigned char nsDnsName[255];
   change2dnsNameFormat(nsDnsName, nsName);
   next = 0;
   while(0 != nsDnsName[next]){
       buf[len_Header+len_Querty+len_Answer+len_zone_name+sizeof(struct R_DATA)+next] = nsDnsName[next];
       next++; 
   }
   buf[len_Header+len_Querty+len_Answer+len_zone_name+sizeof(struct R_DATA)+next] = nsDnsName[next];
   //printf("%d\n", buf[len_Header+len_Querty+len_Answer+len_zone_name+sizeof(struct R_DATA)+next]); 
   int len_nsName;
   len_nsName = next +1;
   int len_Auth;
   len_Auth = len_zone_name+sizeof(struct R_DATA)+len_nsName;
   //end Authoritative


   /*Additional records*/
   next = 0;
   while(0!=nsDnsName[next]){
       buf[len_Header+len_Querty+len_Answer+len_Auth+next] = nsDnsName[next];
       //printf("%d", nsDnsName[next]);
       next++;
   }
   //printf("\n");
   buf[len_Header+len_Querty+len_Answer+len_Auth+next] = nsDnsName[next];

      /*type, class, ttl, data_len start*/
    struct R_DATA *r_data_add1 = NULL;
    r_data_add1 = (struct R_DATA*)&buf[len_Header+len_Querty+len_Answer+len_Auth+len_nsName];
    r_data_add1->type = htons(1);     /*type: A*/
    r_data_add1->_class = htons(1);   /*IPV4 internet class*/
    r_data_add1->ttl = htonl(86400);  /*1D*/
    r_data_add1->data_len = htons(4); 
      /*end type, class, ttl, data_len*/ 
    struct in_addr *ns_ip;
    ns_ip = (struct in_addr*)&buf[len_Header+len_Querty+len_Answer+len_Auth+len_nsName+sizeof(struct R_DATA)];
    ns_ip->s_addr = adr_serv.sin_addr.s_addr; //local ip;
    int len_Add1;
    len_Add1 = len_nsName + sizeof(struct R_DATA) + sizeof(struct in_addr);
 
        z = sendto(s,   /* Socket to send result */
            (unsigned char *)buf, /* The datagram result to snd */
             len_Header+
             len_Querty+
             len_Answer+
             len_Auth+
             len_Add1+
             1,
            0,              /* Flags: no options */
            (struct sockaddr *)&adr_clnt,/* addr */
            len_clnt);  /* Client address length */
	if(z==-1){
            perror ("recv");
           // exit(1);
	}
 
    }
    
 
    /*
     * Close the socket and exit:
     */
    close(s);
    return 0;
}//main

/* This funcotion will convert www.stu.edu.cn to 
 * 3www3stu3stu3edu2cn0, save in dnsName.
 * */
void
change2dnsNameFormat (unsigned char* dnsName, unsigned char* host)
{
    int lock = 0 , i;
    strcat((char*)host,".");
    for(i = 0 ; i < (int)strlen((char*)host) ; i++) {
        if(host[i]=='.') {
            *dnsName++=i-lock;
            for(;lock<i;lock++) {
                *dnsName++=host[lock];
            } //for
            lock++; //or lock=i+1;
        } //if
    } //for
    *dnsName++=0;
}

/*
 * conver 3www3stu3edu2cn0 to www.stu.edu.cn
 * 
 * */
unsigned char* readName(unsigned char *dnsName)
{
        unsigned int p=0;
        int i,j;
        for(i=0;i<(int)strlen((const char*)dnsName);i++){
                p=dnsName[i];
                for(j=0;j<(int)p;j++){
                dnsName[i]=dnsName[i+1];
                i=i+1;
                }
                dnsName[i]='.';
        }
                dnsName[i-1]='\0'; //remove the last dot
                return dnsName;
}

/* Find the ip location from DNSLISTFILE.
 * if find it return 0, save the localtion.
 * else return 1.
 * */
int getLocation(char *ipaddr, char *localtion)
{
        gsize len_groups = 0;
        GKeyFile *keyFile = g_key_file_new ();
        GKeyFileFlags flags = G_KEY_FILE_NONE;
        GError* error = NULL;
        char** groups = NULL;
        char** key = NULL;
        char* value = NULL;
        char filePath[2048];
        sprintf(filePath, "%s%s", data_dir, DNSLISTFILENAME);

        if(!g_key_file_load_from_file(keyFile,(const gchar*)filePath,flags,&error)){
                g_error (error->message);
                return 1;
        }
        groups = g_key_file_get_groups(keyFile, &len_groups);
        gsize len_keys = 0;
        gsize i = 0;
        for(i=0; i<len_groups; i++){
                key = g_key_file_get_keys(keyFile, groups[i], &len_keys, &error);
                gsize j = 0;
                for(j=0; j<len_keys; j++){
                     //printf("key = %s \n", key[j]);
                     value = g_key_file_get_value(keyFile,groups[i],key[j],&error);
                     if(0==strcmp(value, ipaddr)){
                             strcpy(localtion, groups[i]);
                             //printf("group:%s\n",localtion);
                             return 0;
                     }//if
                     //else printf("Not find!\n");
                            //return 1;
                }//for j
        }//for i
        return 1;
}

/* search the A Record from zone file.
 * urlName is the zonefile PATH.
 * localtion is the DNS server location
 * record save the a record(ip address)
 * 
 * first, according the location to find 
 *       the position in the zonefile db.
 * then, start at the where position, 
 *       go next and pre end with NULL.
 * then, compare the |next-where| with
 *       |pre - where|. The smaller one
 *       is the result position.
 * */
int getArecord(unsigned char* urlName, char *localtion, char *record)
{
    GKeyFile *keyFile = g_key_file_new();
    GKeyFileFlags flags = G_KEY_FILE_NONE;
    GError* error = NULL;
    gchar** keys = NULL;
    gchar* value=NULL;
    gsize len_keys;
    int where; //the localtion in the DB position

    if(!g_key_file_load_from_file(keyFile, (const gchar*)urlName, flags, &error)){
         //g_error(error->message);
         return 1;
    }
    keys=g_key_file_get_keys(keyFile, "A record", &len_keys, &error);
    int i=0;
    for(i=0;i<(int)len_keys;i++){
            if(0==strcmp(keys[i], localtion)){
                    where = i;
                    //printf("where=%d\n", where);
                    //value=g_key_file_get_value(keyFile, "A record", localtion, &error);
                    break;
            }
    }

    int next=0;
    i=where;
    for(i=where; i<(int)len_keys;i++){
            value=g_key_file_get_value(keyFile, "A record", keys[i], &error);
            if(0 != strcmp(value, "\0")){
                    next=i;
                    //printf("next=%d\n", next);
                    break;
            }
    }

    int pre;
    i=where;
    for(i=where; i>=0; i--){
            value=g_key_file_get_value(keyFile, "A record", keys[i], &error);
            if(0 != strcmp(value, "\0")){
                    pre=i;
                    //printf("pre=%d\n", pre);
                    break;
            }
    }

    if((abs(pre-where)-abs(next-where))<=0){

            //printf("pre=%d\n", pre);
            //printf("A record location: %s\n", keys[next]);
            value=g_key_file_get_value(keyFile, "A record", keys[pre], &error);

    }
    else{
            //printf("next=%d\n", next);
            //printf("A record location: %s\n", keys[next]);
            value=g_key_file_get_value(keyFile, "A record", keys[next], &error);
    }
    strcpy(record, value);
    
    sprintf(log_content, "调度给访问的Web服务器的城市:%s, IP地址:%s", localtion, record);
    log_2_file(log_content);
    //printf("A record:%s, %s\n", localtion, record);
    return 0;
}

/* 
 * get the A record location which 
 * is the key for getArecord2 function.
 * DB_File: domain_DISTANCEFILESUFFIX
 *
 * */
int getDistanceKey(char *dis_file, char *localtion, char *dis_key)
{
    GKeyFile *keyFile = g_key_file_new();
    GKeyFileFlags flags = G_KEY_FILE_NONE;
    GError* error = NULL;
    gchar** groups = NULL;
    gsize len_groups;

    if(!g_key_file_load_from_file(keyFile, (const gchar*)dis_file, flags, &error)){
         //g_error(error->message);
         return 1;
    }

    groups = g_key_file_get_groups(keyFile, &len_groups);
    int i;
    for(i=0; i<(int)len_groups; i++){
        if(g_key_file_has_key(keyFile, groups[i], localtion, &error)){
            strcpy(dis_key, (char*)groups[i]);//save the new localtion in dis_key.
            return 0;
        }
        else{
             continue;
        }
    }
    return 1;//can not find the lcoaltioin

}
/*
 * Another funciton to get the A record.
 * Read the urlName to search the A record by localtion.
 * Found and the value is not blank: save the A record, return 0
 * Not Found or the value is blank: get the DistanceKey to replace
 * the localtion, then to find the A record.
 * If the getDistanceKey fail, It will use the getArecored function
 * to find a A record.
 * 
 * */
int getArecord2(unsigned char* urlName, char *localtion, char *record)
{
    GKeyFile *keyFile = g_key_file_new();
    GKeyFileFlags flags = G_KEY_FILE_NONE;
    GError* error = NULL;
    gchar* value=NULL;
    char dis_file[2048];
    char dis_key[10]; //new localtion
    int isDis;
    sprintf(dis_file, "%s_%s", urlName, DISTANCEFILESUFFIX);
    //puts(dis_file);

    if(!g_key_file_load_from_file(keyFile, (const gchar*)urlName, flags, &error)){
         return 1;
    }
    if(g_key_file_has_key(keyFile,"A record", localtion, &error)){
            value=g_key_file_get_value(keyFile, "A record", localtion, &error);
            if(0 != strcmp(value,"\0")){
                strcpy(record, value);
                sprintf(log_content, "调度给访问的Web服务器的城市:%s, IP地址:%s", localtion, record);
                log_2_file(log_content);
                //printf("A record:%s, %s\n", localtion, record);
                return 0;
            }
            else{
                isDis = getDistanceKey(dis_file, localtion, dis_key);
                if(0==isDis){
                    value=g_key_file_get_value(keyFile, "A record", (gchar*)dis_key, &error);
                    strcpy(record, value);
                    sprintf(log_content, "调度给访问的Web服务器的城市:%s, IP地址:%s", dis_key, record);
                    log_2_file(log_content);
                    //printf("A record:%s, %s\n", dis_key, record);
                    return 0;
                }
                else{//get distance fail
                   getArecord(urlName, localtion, record);
                    return 0;
                }
            }

    }
    else{
           isDis = getDistanceKey(dis_file, localtion, dis_key);
           if(0==isDis){
               value=g_key_file_get_value(keyFile, "A record", (gchar*)dis_key, &error);
               strcpy(record, value);
               sprintf(log_content, "调度给访问的Web服务器的城市:%s, IP地址:%s", dis_key, record);
               log_2_file(log_content);
               //printf("A record:%s, %s\n", dis_key, record);
               return 0;
           }
           else{//get distance fial
               getArecord(urlName, localtion, record);
               return 0;
           }

    }
}

/* 
 * Prints usage information for this program to STREAM (typically
 * stdout or stderr), and exit the program with EXIT_CODE. Does not
 * return. 
 * */

void
print_usage (FILE* stream, int exit_code)
{
  fprintf (stream, "%s: a simple location DNS Server.\n\n", program_name);
  fprintf (stream, "Usage: %s [ options ]\n\n", program_name);
  fprintf (stream,
           " -d --data_dir the data directory. \n"
                  "\te.g: ./datat/test/\n\n"
           " -h --help Display this usage information.\n\n");
  exit (exit_code);
}

/*
 * parse the argv option, its main job is to set Database 
 * directory.
 * if the -d option is not given, use the default directory
 *     ./data/test/
 * 
 * */
void
parse_opt (int argc, char** argv)
{
  if(1==argc){
      sprintf(data_dir, "./data/test/");
  }
  int next_option;

  const char* const short_options = "d:h";
  const struct option long_options[] = {
    { "data_dir", 1, NULL, 'd' },
    { "help", 0, NULL, 'h' },
    { NULL, 0, NULL, 0 } /* Required at end of array. */
  };

  do {
      next_option = getopt_long (argc, argv, short_options,
                               long_options, NULL);
      switch (next_option)
     {
      case 'h': /* -h or --help */
          print_usage (stdout, 0);

      case 'd': /* -d or --data_dir */
          sprintf(data_dir, "%s", optarg);
          break;


      case '?': /* The user specified an invalid option. */
          print_usage (stderr, 1);

      case -1: /* Done with options. */
        break;

      default: /* Something else: unexpected. */
        break;
    }
  }
  while (next_option != -1);
  int i=0;
  while('\0' != data_dir[i]){
      //printf("%c\n", data_dir[i]);
      i++;
  }
  //printf("%c\n", data_dir[i-1]); //last char..
  
  if('/' != data_dir[i-1]){
       data_dir[i] = '/'; // end with '/' 
  }
  //printf("%s\n", data_dir);
}


/*
 * check the database directory and the dns_ip_list file
 * wether exist.
 * Not exist: exit 0;
 * */
void
check_file_exit(void)
{
    struct stat t;
    if(-1 == stat(data_dir,&t)){// dir not exist.
        printf("Error:\nDirectory: '%s' is not exist!\n", data_dir);
        exit(1);
    }
    char dns_list_file[2048];
    sprintf(dns_list_file, "%s%s", data_dir, DNSLISTFILENAME);
    if(-1 == stat(dns_list_file,&t)){// Local DNS Server IP file not exist.
        printf("Error:\nFile: '%s' is not exist!\n", dns_list_file);
        exit(1);
    }
    
}
void
check_and_update(char *domain_file)
{
    GKeyFile *keyFile = g_key_file_new();
    GKeyFileFlags flags = G_KEY_FILE_NONE;
    GError* error = NULL;
    gchar* value=NULL;
    gchar* new_file = NULL;
    gsize new_file_length = 0;
    gsize key_length = 0;
    char domain_file_path[2048];
    char backup_a_record[1024];

    sprintf(domain_file_path, "%s%s", data_dir, domain_file);
    sprintf(log_content, "查找域名Web服务器更新,配置文件:%s", domain_file_path);
    //log_2_file(log_content);
    //printf("%s\n", domain_file_path);

    if(!g_key_file_load_from_file(keyFile, (const gchar*)domain_file_path, flags, &error)){
         printf("Error no such file\n");
    }
    gchar **keys=NULL;
    keys=g_key_file_get_keys(keyFile, "A record", &key_length, &error);
    int i = 0;
    for(i=0; i < (int)key_length; i++){
         value = g_key_file_get_value(keyFile,"A record",keys[i],NULL);
         if(0 != strcmp(value, "\0")){ //has A record
                //printf("%s:%s\n", keys[i], value);
	            int res;
	            res = check_on_line((char*)value);
	            //printf("res: %d\n", res);
                 if (0 == res){
                     sprintf(log_content, "域名%s的Web服务器%s:%s在线，不需要更新!", domain_file, keys[i], value);
                     log_2_file(log_content);
                     //printf("Online\n");
                     continue;
                 }
                 if (1 == res){
                     //printf("OFFline\n");
                      sprintf(log_content, "注意:域名%s的Web服务器%s:%s不在线，需要更新!", domain_file, keys[i], value);
                      log_2_file(log_content);
	                  sprintf(backup_a_record, "%s=%s", keys[i], value);
	                  g_key_file_set_comment(keyFile, "A record", keys[i], (gchar*)backup_a_record, &error);
	                  g_key_file_set_value(keyFile, "A record", keys[i], "");
	                  new_file = g_key_file_to_data (keyFile, &new_file_length, &error);
		              //printf("%s\n", new_file);
		              FILE *fp;
                      pthread_rwlock_wrlock(&rwlock);
		              if ((fp=fopen(domain_file_path, "w")) == NULL ){
	                     printf("Can not open domain file\n");
		                 continue;
		              }
		              if(1 != (fwrite(new_file, new_file_length, 1, fp))){
		                 //printf("Write ERROR, when update A record\n");
                         sprintf(log_content, "注意:更新不了域名%s对应的Web服务器信息文件!", domain_file);
                         log_2_file(log_content);
		              }
                      else{
                         sprintf(log_content, "更新域名%s配置文件!成功!", domain_file);
                         log_2_file(log_content);
                      }
		      fclose(fp);
                      pthread_rwlock_unlock(&rwlock);
		      continue;
                 }
          }
	      else{ //A record is NULL
             continue;
	      }
    }//for
}

void
update_config_files(void){

     DIR   *dirptr   =   NULL;
     struct   dirent   *entry;
     char *domain_file = NULL;
     if((dirptr = opendir(data_dir)) ==  NULL){
         printf("open dir error!\n");
         closedir(dirptr);
	 //return 1;
     }
     else{
	 while(1){
         while((entry = readdir(dirptr))){
             if(0 != strstr(entry->d_name, "_distance.db")){
                 //printf( "%s\n",   entry->d_name);
                   domain_file = strtok(entry->d_name, "_");
                   //printf("%s\n", domain_file);
                   check_and_update(domain_file);
                   printf("check one!\n");
              }
              continue;
         }
	     sleep(1800);
	 }
         closedir(dirptr);
    }

}
